<?php

namespace PhpYes\Com;

class Version
{

    /**
     * @param string $version
     * @return string
     */
    public static function trim_version($version)
    {
        $version = isset($version) ? ltrim(strval($version)) : '';
        if ($version === '') {
            return '';
        }
        return rtrim($version, " .\t\n\r\0\x0B");
    }

    /**
     * @param string $version
     * @return int[]
     */
    public static function split_version($version)
    {
        $version = isset($version) ? self::trim_version($version) : '';
        if ($version === '') {
            return [];
        }

        $strs = explode('.', $version);
        $ints = [];
        foreach ($strs as $str) {
            $ints[] = empty($str) ? 0 : intval($str);
        }
        return $ints;
    }

    /**
     * @param int[]|string[] $ints
     * @return string - standard version
     */
    public static function make_version($ints)
    {
        if (empty($ints)) {
            return '';
        }

        $version = [];
        foreach ($ints as $int) {
            $version[] = empty($int) ? 0 : intval($int);
        }
        return implode('.', $version);
    }

    /**
     * standard version
     * @param string $version
     * @return string - standard version
     */
    public static function std_version($version)
    {
        $version = isset($version) ? self::trim_version($version) : '';
        if ($version === '') {
            return '';
        }

        $strs = explode('.', $version);
        $version = [];
        foreach ($strs as $str) {
            $version[] = empty($str) ? 0 : intval($str);
        }
        return implode('.', $version);
    }

    /**
     * @param int[]|string[] $v_ints
     * @param int[]|string[] $ints
     * @return bool
     */
    public static function v_ints_start_with($v_ints, $ints)
    {
        $len = 0;
        if (empty($v_ints)) {
            return empty($ints);
        } elseif (empty($ints)) {
            return true;
        } else {
            $len = count($ints);
            if (count($v_ints) < $len) {
                return false;
            }
        }

        for ($i = 0; $i < $len; $i++) {
            $int1 = empty($v_ints[$i]) ? 0 : intval($v_ints[$i]);
            $int2 = empty($ints[$i]) ? 0 : intval($ints[$i]);
            if ($int1 != $int2) {
                return false;
            }
        }
        return true;
    }

    /**
     * !!! 前缀相同时，length 小的反而 version_ints 大，例如 : 1 > 1.2 > 1.2.3
     * @param int[]|string[] $ints1 - 要求都是有效位
     * @param int[]|string[] $ints2 - 要求都是有效位
     * @return int - <0 : $ints1 < $ints2, =0 : $ints1 = $ints2, >0 : $ints1 > $ints2
     */
    public static function v_ints_cmp($ints1, $ints2)
    {
        if (empty($ints1)) {
            return empty($ints2) ? 0 : 1;
        } elseif (empty($ints2)) {
            return -1;
        }

        $len1 = count($ints1);
        $len2 = count($ints2);
        $len = $len1 < $len2 ? $len1 : $len2;
        for ($i = 0; $i < $len; $i++) {
            $int1 = empty($ints1[$i]) ? 0 : intval($ints1[$i]);
            $int2 = empty($ints2[$i]) ? 0 : intval($ints2[$i]);
            if ($int1 === $int2) {
                continue;
            }
            return $int1 - $int2;
        }

        if ($len1 < $len2) {
            return 1;
        }
        return $len1 == $len2 ? 0 : -1;
    }

    /**
     * @param int[][]|string[][] $v_arrs - $v_arrs 是关联数组 或者 哈希数组 或者 对象 时也是可以的
     * @param bool $order_desc - order_desc ? 'desc' : 'asc'
     * @return int[][]|string[][] - return a new array(shallow-copied) with the elements sorted
     */
    public static function sort_v_arrs($v_arrs, $order_desc = false)
    {
        if (empty($v_arrs)) {
            return [];
        }
        $v_arrs = array_values($v_arrs);
        if (count($v_arrs) == 1) { // v_arrs.length == 1 时不用排序
            return [$v_arrs[0]];
        }

        // usort 会触发 php 数组的写时复制 从而获得一个副本
        // $v_arrs1 = []; $v_arrs2 = sort_v_arrs($v_arrs1);
        // $v_arrs1 不变，$v_arrs2 却是排序好了的数组了
        if ($order_desc) {
            usort($v_arrs, function ($arr1, $arr2) {
                return \PhpYes\Com\Version::v_ints_cmp($arr2, $arr1);
            });
        } else {
            usort($v_arrs, function ($arr1, $arr2) {
                return \PhpYes\Com\Version::v_ints_cmp($arr1, $arr2);
            });
        }
        return $v_arrs;
    }

}